﻿const STATUS_MAP = {
  Draft: { value: "Draft", text: "草稿", style: "draft" },
  Published: { value: "Published", text: "报名中", style: "published" },
  Withdraw: { value: "Withdraw", text: "已下线", style: "withdraw" }
};

const UNKNOWN_STATUS = { value: "Unknown", text: "未知状态", style: "default" };

const LABELS = {
  placeholderNoCover: "暂无封面",
  timeLabel: "活动时间",
  locationLabel: "活动地点",
  registrationLabel: "报名时间",
  publisherLabel: "发布者",
  registrationTitle: "报名情况",
  introductionTitle: "活动介绍",
  requirementTitle: "报名要求",
  groupTitle: "活动分组",
  registrantTitle: "报名成员",
  viewRegistrantsTitle: "查看报名者",
  viewRegistrantsGroupTitle: "报名分组",
  viewRegistrantsSummary: "总报名人数",
  viewRegistrantsEmpty: "暂无报名成员",
  viewRegistrantsLimitedHint: "仅发布者可查看报名详情",
  registerTitle: "活动报名",
  updateRegistrationTitle: "修改报名信息",
  groupSelectTitle: "选择分组",
  groupSelectUpdateHint: "如需调整，请重新勾选参与分组",
  currentGroupTag: "已报名",
  groupQuotaLabel: "报名人数：",
  groupFullHint: "名额已满",
  noGroupsAvailable: "当前暂无可报名的分组",
  loadingFields: "正在加载报名信息...",
  extraFieldsTitle: "补充信息",
  extraFieldsHint: "除特别说明外，标“*”项为必填",
  fieldPlaceholder: "请输入",
  noExtraFields: "无需额外填写信息",
  confirmRegistrationAction: "提交报名",
  updateRegistrationAction: "保存修改",
  cancelRegistrationAction: "取消报名"
};

const STATE_TEXTS = {
  loading: "正在加载...",
  retry: "重新加载"
};

const MAX_PREVIEW_COUNT = 6;

const pad2 = value => {
  const num = typeof value === "number" ? value : parseInt(value, 10);
  if (Number.isNaN(num)) return "00";
  return num < 10 ? `0${num}` : `${num}`;
};

const toDate = source => {
  if (!source) return null;

  if (source instanceof Date) {
    return Number.isNaN(source.getTime()) ? null : source;
  }

  if (typeof source === "object" && source.$date) {
    return toDate(source.$date);
  }

  let normalized = source;
  if (typeof source === "string") {
    normalized = source.trim();
    if (/^\d+$/.test(normalized)) {
      const timestamp = Number(normalized);
      return Number.isNaN(timestamp) ? null : new Date(timestamp);
    }
    normalized = normalized.replace(/\//g, "-");
    if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2})?$/.test(normalized)) {
      normalized = normalized.replace(" ", "T");
    }
    if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(normalized)) {
      normalized = `${normalized}:00`;
    }
    if (/^\d{4}-\d{2}-\d{2}$/.test(normalized)) {
      normalized = `${normalized}T00:00:00`;
    }
  }

  const result = new Date(normalized);
  return Number.isNaN(result.getTime()) ? null : result;
};

const toTrimmedString = value => (typeof value === "string" ? value.trim() : "");

const decodeHTML = value => {
  if (value === null || value === undefined) return "";
  let text = String(value);

  const decodeCodePoint = code => {
    if (!Number.isFinite(code) || code < 0) return "";
    try {
      return typeof String.fromCodePoint === "function"
        ? String.fromCodePoint(code)
        : String.fromCharCode(code);
    } catch (error) {
      return "";
    }
  };

  const namedEntities = {
    "&nbsp;": " ",
    "&lt;": "<",
    "&gt;": ">",
    "&quot;": "\"",
    "&#39;": "'"
  };

  const decodeOnce = source => {
    let result = source.replace(/&amp;/g, "&");

    result = result.replace(/&#x([0-9a-fA-F]+);?/g, (match, hex) => {
      const code = parseInt(hex, 16);
      const char = decodeCodePoint(code);
      return char || match;
    });

    result = result.replace(/&#(\d+);?/g, (match, dec) => {
      const code = parseInt(dec, 10);
      const char = decodeCodePoint(code);
      return char || match;
    });

    Object.keys(namedEntities).forEach(entity => {
      const replacement = namedEntities[entity];
      if (replacement !== undefined) {
        result = result.replace(new RegExp(entity, "g"), replacement);
      }
    });

    return result;
  };

  for (let i = 0; i < 5; i += 1) {
    const decoded = decodeOnce(text);
    if (decoded === text) break;
    text = decoded;
  }

  return text;
};

const toISOStringString = value => {
  const date = toDate(value);
  return date ? date.toISOString() : "";
};

const formatGender = value => {
  if (value === null || value === undefined || value === "") return "";
  if (typeof value === "number") {
    if (value === 1) return "男";
    if (value === 2) return "女";
    return String(value);
  }
  const text = toTrimmedString(value);
  if (!text) return "";
  if (text === "男" || text === "女") return text;
  const lower = text.toLowerCase();
  if (lower === "1" || lower === "male" || lower === "m") return "男";
  if (lower === "2" || lower === "female" || lower === "f") return "女";
  return text;
};

const STUDENT_TYPE_LABELS = {
  1: "本科生",
  2: "硕士研究生",
  3: "博士研究生"
};

const formatStudentType = value => {
  if (value === null || value === undefined || value === "") return "";
  if (typeof value === "number") return STUDENT_TYPE_LABELS[value] || String(value);
  const text = toTrimmedString(value);
  if (!text) return "";
  if (/^[123]$/.test(text)) {
    const numberValue = Number(text);
    return STUDENT_TYPE_LABELS[numberValue] || text;
  }
  const lower = text.toLowerCase();
  if (text.includes("本科") || lower.includes("undergraduate")) {
    return STUDENT_TYPE_LABELS[1];
  }
  if (
    text.includes("硕") ||
    text.includes("研") ||
    lower.includes("master") ||
    lower.includes("postgraduate") ||
    lower.includes("graduate")
  ) {
    return STUDENT_TYPE_LABELS[2];
  }
  if (
    text.includes("博") ||
    lower.includes("phd") ||
    lower.includes("doctor") ||
    lower.includes("doctoral")
  ) {
    return STUDENT_TYPE_LABELS[3];
  }
  return text;
};

const formatEnrollmentYear = value => {
  if (value === null || value === undefined || value === "") return "";
  if (value instanceof Date && !Number.isNaN(value.getTime())) {
    const year = value.getFullYear();
    return year ? `${year}级` : "";
  }
  if (typeof value === "number") {
    if (value >= 1900 && value <= 2100) return `${value}级`;
    return String(value);
  }
  const text = toTrimmedString(value);
  if (!text) return "";
  if (/^\d{4}$/.test(text)) return `${text}级`;
  const parsedDate = toDate(text);
  if (parsedDate) {
    const year = parsedDate.getFullYear();
    return year ? `${year}级` : text;
  }
  const yearMatch = text.match(/(\d{4})/);
  if (yearMatch && yearMatch[1]) return `${yearMatch[1]}级`;
  if (text.endsWith("级") || text.endsWith("年级")) return text;
  return text;
};

const buildRegistrationFieldDefinitions = fields => {
  const list = [];
  const map = new Map();
  if (Array.isArray(fields)) {
    fields.forEach(field => {
      const idSource =
        field.fieldID || field.FieldID || field._id || field.id || field.Id || "";
      const id = idSource || idSource === 0 ? String(idSource).trim() : "";
      if (!id) return;
      const name = toTrimmedString(field.fieldName || field.FieldName || field.name || "");
      const def = {
        fieldID: id,
        fieldName: name,
        isOptional: !!field.isOptional
      };
      list.push(def);
      map.set(id, def);
    });
  }
  return { list, map };
};

const normalizeRegistrationFieldValues = (definitionInfo, values) => {
  const definitions =
    definitionInfo && Array.isArray(definitionInfo.list) ? definitionInfo.list : [];
  const valueMap = new Map();

  if (Array.isArray(values)) {
    values.forEach(field => {
      const idSource =
        field.fieldID || field.FieldID || field._id || field.id || field.Id || "";
      const id = idSource || idSource === 0 ? String(idSource).trim() : "";
      if (!id) return;
      const name = toTrimmedString(field.fieldName || field.FieldName || field.name || "");
      const content = field.fieldContent || field.FieldContent || field.value || "";
      valueMap.set(id, {
        fieldID: id,
        fieldName: name,
        fieldContent: content,
        isOptional: !!field.isOptional
      });
    });
  }

  const result = [];

  definitions.forEach(def => {
    const stored = valueMap.get(def.fieldID);
    result.push({
      fieldID: def.fieldID,
      fieldName: def.fieldName || (stored && stored.fieldName) || "",
      fieldContent: stored ? stored.fieldContent : "",
      isOptional: !!def.isOptional
    });
    if (stored) {
      valueMap.delete(def.fieldID);
    }
  });

  valueMap.forEach(stored => {
    result.push({
      fieldID: stored.fieldID,
      fieldName: stored.fieldName || "",
      fieldContent: stored.fieldContent || "",
      isOptional: !!stored.isOptional
    });
  });

  return result;
};

const isCloudFile = url => typeof url === "string" && url.indexOf("cloud://") === 0;

const buildSelectionMap = ids => {
  const map = {};
  if (Array.isArray(ids)) {
    ids.forEach(id => {
      if (id === null || id === undefined) return;
      const key = typeof id === "string" ? id : String(id);
      if (key) map[key] = true;
    });
  }
  return map;
};

const createRegistrationModalState = (overrides = {}) =>
  Object.assign(
    {
      visible: false,
      mode: "create",
      loading: false,
      submitting: false,
      needCollectInfo: false,
      fields: [],
      selectedGroupIDs: [],
      selectionMap: {},
      error: "",
      canCancel: false
    },
    overrides
  );

const createRegistrantDetailState = (overrides = {}) =>
  Object.assign(
    {
      visible: false,
      loading: false,
      deleting: false,
      error: "",
      registrant: null,
      expandedSections: {
        groups: true,
        fields: false
      }
    },
    overrides
  );

Page({
  data: {
    loading: true,
    errorMessage: "",
    activity: null,
    labels: LABELS,
    stateTexts: STATE_TEXTS,
    actionLoading: {},
    registrationModal: createRegistrationModalState()
  },

  onLoad(options = {}) {
    this.tempFileCache = {};
    this.registrationFieldCache = {};
    this.registrationInfoCache = {};
    this.registrantDetailCache = {};
    this.currentActivityId = "";

    const activityId = options.activityID || options.activityId || options.id || "";

    if (!activityId) {
      this.setData({
        loading: false,
        errorMessage: "未找到活动编号，无法加载详情"
      });
      return;
    }

    this.fetchActivityDetail(activityId);
  },

  onPullDownRefresh() {
    const activityId = (this.data.activity && this.data.activity.id) || this.currentActivityId;
    if (!activityId) {
      wx.stopPullDownRefresh();
      return;
    }
    this.fetchActivityDetail(activityId);
  },

  fetchActivityDetail(activityId) {
    this.currentActivityId = activityId;
    this.setData({ loading: true, errorMessage: "" });

    this.invokeCloudFunction({
      name: "queryActivityInfo",
      data: { activityID: activityId },
      loadingTitle: "加载中...",
      success: res => {
        const payload = res && (res.result || res.data || res);
        if (!payload || !payload.activityID) {
          this.handleFailure("未获取到活动详情");
          return;
        }
        this.currentActivityDetail = payload;
        const normalized = this.normalizeActivity(payload);
        const fileIDs = this.collectFileIDs(normalized);

        this.resolveTempURLs(fileIDs)
          .then(cache => {
            const activityWithAssets = this.applyTempURLs(normalized, cache);
            this.renderActivity(activityWithAssets);
          })
          .catch(err => {
            console.error("resolveTempURLs failed", err);
            this.renderActivity(normalized);
          });
      },
      fail: err => {
        console.error("queryActivityInfo failed", err);
        this.handleFailure("活动详情加载失败，请稍后重试");
      },
      complete: () => {
        wx.stopPullDownRefresh();
      }
    });
  },

  renderActivity(activity) {
    this.setData({
      loading: false,
      errorMessage: "",
      activity,
      actions: activity.actions || [],
      actionLoading: {},
      registrationModal: createRegistrationModalState()
    });
  },

  handleFailure(message) {
    this.setData({
      loading: false,
      errorMessage: message || "活动详情加载失败",
      activity: null,
      actions: [],
      actionLoading: {},
      registrationModal: createRegistrationModalState()
    });
  },

  normalizeActivity(detail) {
    const statusValue = this.parseStatus(detail.activityStatus);
    let status = STATUS_MAP[statusValue] || UNKNOWN_STATUS;
    let statusVisible = status.value !== "Unknown" && !!status.text;
    const isPublisher = this.isCurrentUserPublisher(detail.publisherOpenID);
    const isRegistrant = !!detail.isRegistrant;

    const registrationStart = toDate(detail.registrationStartTime);
    const registrationEnd = toDate(detail.registrationEndTime);
    const registrationPeriodDisplay =
      this.formatRange(registrationStart, registrationEnd) || "报名时间待定";

    const groupsRaw = Array.isArray(detail.activityGroups) ? detail.activityGroups : [];
    const joinedGroupIDs = Array.isArray(detail.registrationGroupIDs)
      ? detail.registrationGroupIDs
      : [];

    const groups = groupsRaw.map((group, index) =>
      this.normalizeGroup(group, index, joinedGroupIDs)
    );

    const totals = this.sumGroups(groups);
    const registrationOpen = this.isWithinRange(registrationStart, registrationEnd);
    const hasQuota = totals.total === 0 || totals.registered < totals.total;
    const allowSignup = status.value === "Published" && registrationOpen && hasQuota;

    const registrantPreview = this.buildRegistrantPreview(groups);
    const moreRegistrantsCount = Math.max(totals.registered - registrantPreview.length, 0);

    if (status.value === "Published") {
      const now = Date.now();
      const startTime = registrationStart ? registrationStart.getTime() : null;
      const endTime = registrationEnd ? registrationEnd.getTime() : null;

      if (startTime && now < startTime) {
        status = { value: "Published", text: "报名未开始", style: "default" };
        statusVisible = true;
      } else if (endTime && now > endTime) {
        status = { value: "Closed", text: "报名已截止", style: "default" };
        statusVisible = true;
      }
    }

    const actionHint = this.buildActionHint({
      isPublisher,
      isRegistrant,
      allowSignup,
      registrationOpen,
      hasQuota,
      statusValue: status.value
    });

    const registrationTotals = {
      registered: totals.registered,
      totalSlots: totals.total,
      remaining: totals.total > 0 ? Math.max(totals.total - totals.registered, 0) : null
    };

    const progressText =
      registrationTotals.totalSlots && registrationTotals.totalSlots > 0
        ? `${registrationTotals.registered}/${registrationTotals.totalSlots}`
        : `${registrationTotals.registered}`;
    const progressPercent =
      registrationTotals.totalSlots && registrationTotals.totalSlots > 0
        ? Math.min(100, Math.round((registrationTotals.registered / registrationTotals.totalSlots) * 100))
        : 0;

    return {
      id: detail.activityID || "",
      name: detail.activityName || "未命名活动",
      location: detail.activityLocation || "地点待定",
      publisherName: detail.publisherName || "",
      publisherOpenID: detail.publisherOpenID || "",
      image: detail.activityImageURL || "",
      coverRaw: detail.activityImageURL || "",
      status,
      statusVisible,
      registrationPeriodDisplay,
      timeDisplay: this.formatActivityTime(groups) || "时间待定",
      details: this.splitText(detail.activityDetails),
      requirements: this.splitText(detail.activityRequirements),
      registrantPreview,
      moreRegistrantsCount,
      registrationTotals,
      progressText,
      progressPercent,
      groups,
      joinedGroupIDs,
      isRegistrant,
      isPublisher,
      registrationOpen,
      hasQuota,
      allowSignup,
      actionHint,
      actions: this.buildActions({
        isPublisher,
        isRegistrant,
        allowSignup,
        statusValue: status.value,
        registrationOpen,
        hasQuota
      })
    };
  },

  normalizeGroup(group, index, joinedGroupIDs) {
    const start = toDate(group.groupStartTime);
    const end = toDate(group.groupEndTime);

    const registrantsRaw = Array.isArray(group.registrants) ? group.registrants : [];

    const registrants = registrantsRaw.map((item, idx) => {
      const avatarRaw = item && item.avatar ? item.avatar : "";
      return {
        key: `${group.groupID || index}-${idx}`,
        nickname: (item && item.nickname) || "匿名报名者",
        avatar: avatarRaw,
        avatarRaw,
        isCurrentUser: !!(item && item.isCurrentUser)
      };
    });

    const registeredCount =
      typeof group.groupRegisteredCount === "number"
        ? group.groupRegisteredCount
        : registrants.length;

    const quota =
      typeof group.groupRegistrationCount === "number" ? group.groupRegistrationCount : 0;

    const isCurrentUser =
      joinedGroupIDs.indexOf(group.groupID) !== -1 ||
      registrants.some(item => item.isCurrentUser);

    const isFull = quota > 0 && registeredCount >= quota;

    const checkInActiveRaw =
      typeof group.checkInActive === "boolean"
        ? group.checkInActive
        : typeof group.isCheckInActive === "boolean"
        ? group.isCheckInActive
        : group.IsCheckInActive;
    const checkOutActiveRaw =
      typeof group.checkOutActive === "boolean"
        ? group.checkOutActive
        : typeof group.isCheckOutActive === "boolean"
        ? group.isCheckOutActive
        : group.IsCheckOutActive;
    const checkInStart =
      group.checkInStartTime || group.CheckInStartTime || group.checkinStartTime || null;
    const checkOutStart =
      group.checkOutStartTime || group.CheckOutStartTime || group.checkoutStartTime || null;
    const checkInCode =
      group.checkInCode ||
      group.checkInCodeOrURL ||
      group.CheckInCodeOrURL ||
      group.checkinCodeOrURL ||
      "";
    const checkOutCode =
      group.checkOutCode ||
      group.checkOutCodeOrURL ||
      group.CheckOutCodeOrURL ||
      group.checkoutCodeOrURL ||
      "";

    return {
      groupID: group.groupID || `group-${index}`,
      groupName: group.groupName || `分组 ${index + 1}`,
      timeRangeDisplay: this.formatRange(start, end) || "时间待定",
      remark: decodeHTML(group.remark || group.Remark || ""),
      registrants,
      registeredCount,
      quota,
      quotaText: quota > 0 ? `${registeredCount}/${quota}` : `${registeredCount}`,
      availableSlots: quota > 0 ? Math.max(quota - registeredCount, 0) : null,
      isFull,
      isSelectable: quota === 0 || registeredCount < quota,
      isCurrentUser,
      checkInActive: !!checkInActiveRaw,
      checkOutActive: !!checkOutActiveRaw,
      checkInStartTime: checkInStart,
      checkOutStartTime: checkOutStart,
      checkInCode: typeof checkInCode === "string" ? checkInCode : "",
      checkOutCode: typeof checkOutCode === "string" ? checkOutCode : ""
    };
  },

  sumGroups(groups) {
    return groups.reduce(
      (result, group) => {
        result.registered += group.registeredCount;
        result.total += group.quota;
        return result;
      },
      { registered: 0, total: 0 }
    );
  },

  formatActivityTime(groups) {
    if (!Array.isArray(groups) || groups.length === 0) return "";
    const parts = groups.map(group => group.timeRangeDisplay).filter(Boolean);
    return parts.length > 0 ? parts.join(" / ") : "";
  },

  formatRange(start, end) {
    const startText = start ? this.formatDate(start) : "";
    const endText = end ? this.formatDate(end) : "";
    if (startText && endText) return `${startText} - ${endText}`;
    return startText || endText || "";
  },

  formatDate(date) {
    if (!date) return "";
    const year = date.getFullYear();
    const month = pad2(date.getMonth() + 1);
    const day = pad2(date.getDate());
    const hour = pad2(date.getHours());
    const minute = pad2(date.getMinutes());
    return `${year}年${month}月${day}日 ${hour}:${minute}`;
  },

  formatDateTime(value) {
    const date = toDate(value);
    if (!date) return "";
    const year = date.getFullYear();
    const month = pad2(date.getMonth() + 1);
    const day = pad2(date.getDate());
    const hour = pad2(date.getHours());
    const minute = pad2(date.getMinutes());
    return `${year}-${month}-${day} ${hour}:${minute}`;
  },

  splitText(content) {
    if (!content) return [];
    return String(content)
      .replace(/\r\n/g, "\n")
      .split("\n")
      .map(item => item.trim())
      .filter(item => item.length > 0);
  },

  parseStatus(value) {
    if (value === null || value === undefined) return "Unknown";

    const mapping = {
      Draft: "Draft",
      \u8349\u7a3f: "Draft",
      draft: "Draft",

      Published: "Published",
      \u53d1\u5e03\u4e2d: "Published",
      \u5df2\u53d1\u5e03: "Published",
      \u62a5\u540d\u4e2d: "Published",
      published: "Published",

      Withdraw: "Withdraw",
      \u5df2\u4e0b\u7ebf: "Withdraw",
      \u4e0b\u7ebf: "Withdraw",
      withdraw: "Withdraw",
      \u5df2\u64a4\u9500: "Withdraw",
      \u64a4\u9500: "Withdraw",
      \u5df2\u64a4\u56de: "Withdraw",
      \u64a4\u56de: "Withdraw"
    };

    if (typeof value === "string") {
      const trimmed = value.trim();
      if (!trimmed) return "Unknown";
      if (/^\d+$/.test(trimmed)) {
        value = Number(trimmed);
      } else {
        const lower = trimmed.toLowerCase();
        if (mapping[trimmed]) return mapping[trimmed];
        if (mapping[lower]) return mapping[lower];
        if (lower === "withdrawn") return "Withdraw";
        return trimmed;
      }
    }

    if (typeof value === "number") {
      if (value === 1 || value === 0) return "Draft";
      if (value === 2) return "Published";
      if (value === 3) return "Withdraw";
      return "Unknown";
    }

    return typeof value === "string" ? value : "Unknown";
  },

  isWithinRange(start, end) {
    const now = Date.now();
    const startTime = start ? start.getTime() : null;
    const endTime = end ? end.getTime() : null;
    if (startTime && now < startTime) return false;
    if (endTime && now > endTime) return false;
    return true;
  },

  buildActions({
    isPublisher,
    isRegistrant,
    allowSignup,
    statusValue,
    registrationOpen
  }) {
    if (statusValue === "Withdraw") {
      return [];
    }

    const participantActions = this.buildParticipantActions({
      isRegistrant,
      allowSignup,
      registrationOpen,
      isPublisher,
      statusValue
    });

    if (isPublisher) {
      const publisherActions = this.buildPublisherActions({ statusValue });
      const merged = participantActions.slice();
      publisherActions.forEach(action => {
        if (!merged.some(item => item.key === action.key)) {
          merged.push(action);
        }
      });
      return merged;
    }

    return participantActions;
  },

  buildParticipantActions({
    isRegistrant,
    allowSignup,
    registrationOpen,
    isPublisher,
    statusValue
  }) {
    if (isPublisher && statusValue === "Draft") {
      return [{ key: "publish", text: "发布活动", type: "primary" }];
    }

    if (isRegistrant) {
      const actions = [
        { key: "checkin", text: "签到", type: "primary" },
        { key: "update", text: "修改报名信息", type: "secondary" }
      ];

      if (!isPublisher) {
        actions.push({ key: "cancel", text: "取消报名", type: "danger" });
      }

      return actions;
    }

    const registerAllowed = !!allowSignup && registrationOpen;
    return [
      {
        key: "register",
        text: registerAllowed ? "立即报名" : "报名已截止",
        type: registerAllowed ? "primary" : "disabled",
        disabled: !registerAllowed
      }
    ];
  },

  buildPublisherActions({ statusValue }) {
    const actions = [];
    if (statusValue === "Draft") {
      actions.push({ key: "edit", text: "编辑活动", type: "primary" });
      actions.push({ key: "delete", text: "删除活动", type: "danger" });
      return actions;
    }
    if (statusValue === "Published" || statusValue === "Closed") {
      actions.push({ key: "checkin", text: "签到", type: "primary" });
      actions.push({ key: "withdraw", text: "撤回活动", type: "danger" });
      return actions;
    }
    if (statusValue === "Withdraw") {
      return actions;
    }
    actions.push({ key: "checkin", text: "签到", type: "primary" });
    return actions;
  },

  buildActionHint({ isPublisher, isRegistrant, allowSignup, registrationOpen, hasQuota, statusValue }) {
    if (isRegistrant) {
      return "您已报名该活动，可在此签到、修改或取消报名。";
    }
    if (isPublisher) {
      const restriction = this.describeSignupRestriction({ statusValue, registrationOpen, hasQuota });
      if (allowSignup) {
        return "您是发布者，也可以报名体验本活动。";
      }
      return restriction || "您是发布者，可在此管理报名信息。";
    }
    if (allowSignup) {
      return "报名已开启，请选择分组后完成报名。";
    }
    return this.describeSignupRestriction({ statusValue, registrationOpen, hasQuota });
  },

  describeSignupRestriction({ statusValue, registrationOpen, hasQuota }) {
    if (statusValue !== "Published") return "活动尚未开放报名";
    if (!registrationOpen) return "报名时间未到或已结束";
    if (!hasQuota) return "名额已满，无法继续报名";
    return "";
  },

  buildRegistrantPreview(groups) {
    const preview = [];
    groups.forEach(group => {
      group.registrants.forEach(registrant => {
        if (preview.length < MAX_PREVIEW_COUNT) {
          preview.push({ avatar: registrant.avatar, avatarRaw: registrant.avatarRaw });
        }
      });
    });
    return preview;
  },

  collectFileIDs(activity) {
    const ids = [];
    if (activity.coverRaw && isCloudFile(activity.coverRaw)) {
      ids.push(activity.coverRaw);
    }
    (activity.groups || []).forEach(group => {
      (group.registrants || []).forEach(registrant => {
        if (registrant.avatarRaw && isCloudFile(registrant.avatarRaw)) {
          ids.push(registrant.avatarRaw);
        }
      });
    });
    (activity.registrantPreview || []).forEach(item => {
      if (item.avatarRaw && isCloudFile(item.avatarRaw)) {
        ids.push(item.avatarRaw);
      }
    });
    return Array.from(new Set(ids));
  },

  resolveTempURLs(fileIDs) {
    if (!Array.isArray(fileIDs) || fileIDs.length === 0) {
      return Promise.resolve(this.tempFileCache || {});
    }

    const cache = this.tempFileCache || (this.tempFileCache = {});
    const pending = fileIDs.filter(id => !cache[id]);
    if (pending.length === 0) {
      return Promise.resolve(cache);
    }

    return wx.cloud
      .getTempFileURL({ fileList: Array.from(new Set(pending)) })
      .then(res => {
        const list = (res && res.fileList) || [];
        list.forEach(file => {
          if (file.status === 0 && file.tempFileURL) {
            cache[file.fileID] = file.tempFileURL;
          }
        });
        return cache;
      })
      .catch(err => {
        console.error("getTempFileURL failed", err);
        return cache;
      });
  },

  applyTempURLs(activity, cache) {
    const resolvedCover = isCloudFile(activity.coverRaw)
      ? cache[activity.coverRaw] || activity.coverRaw
      : activity.coverRaw;

    const groups = (activity.groups || []).map(group => {
      const registrants = (group.registrants || []).map(registrant => {
        const avatar = isCloudFile(registrant.avatarRaw)
          ? cache[registrant.avatarRaw] || registrant.avatarRaw
          : registrant.avatarRaw;
        return Object.assign({}, registrant, { avatar });
      });
      return Object.assign({}, group, { registrants });
    });

    const preview = (activity.registrantPreview || []).map(item => {
      const avatar = isCloudFile(item.avatarRaw)
        ? cache[item.avatarRaw] || item.avatarRaw
        : item.avatarRaw;
      return Object.assign({}, item, { avatar });
    });

    return Object.assign({}, activity, {
      cover: resolvedCover,
      image: resolvedCover,
      groups,
      registrantPreview: preview
    });
  },

  handleRetryTap() {
    const activityId = (this.data.activity && this.data.activity.id) || this.currentActivityId;
    if (!activityId) return;
    this.fetchActivityDetail(activityId);
  },

  handlePreviewImage() {
    const activity = this.data.activity;
    if (!activity || !activity.image) return;
    wx.previewImage({ urls: [activity.image] });
  },

  navigateToEditActivity(activityId) {
    const targetId = activityId ? String(activityId).trim() : "";
    if (!targetId) return;
    wx.navigateTo({
      url: `/pages/editActivity/editActivity?activityID=${encodeURIComponent(targetId)}`
    });
  },

  handlePublishActivity(activity) {
    const target = activity || this.data.activity;
    if (!target || !target.id) return;
    if (!target.status || target.status.value !== "Draft") {
      wx.showToast({ title: "仅草稿活动可发布", icon: "none" });
      return;
    }
    if (this.data.actionLoading && this.data.actionLoading.publish) return;

    wx.showModal({
      title: "发布活动",
      content: "确认立即发布该活动？",
      confirmText: "发布",
      cancelText: "取消",
      success: res => {
        if (!res || !res.confirm) return;
        this.publishActivity(target);
      }
    });
  },

  publishActivity(activity) {
    if (!activity || !activity.id) return;
    this.updateActionLoading("publish", true);
    const activityId = activity.id;

    this.loadRegistrationFields(activityId, { showLoading: false })
      .then(result => {
        const fields = (result && result.fields) || [];
        const payload = this.buildPublishPayload(activity, fields);
        if (!payload) {
          this.updateActionLoading("publish", false);
          wx.showToast({ title: "活动信息不完整，无法发布", icon: "none" });
          return;
        }
        this.invokeCloudFunction({
          name: "alterActivityInfo",
          data: payload,
          loadingTitle: "处理中...",
          success: res => {
            const output = res && (res.result || res.data || res);
            if (output && output.success) {
              wx.showToast({ title: "发布成功", icon: "success" });
              this.fetchActivityDetail(activityId);
            } else {
              const message =
                (output && (output.error || output.message)) || "发布失败，请稍后重试";
              wx.showToast({ title: message, icon: "none" });
            }
          },
          fail: err => {
            console.error("alterActivityInfo publish failed", err);
            wx.showToast({ title: "网络异常，发布失败", icon: "none" });
          },
          complete: () => {
            this.updateActionLoading("publish", false);
          }
        });
      })
      .catch(error => {
        console.error("loadRegistrationFields for publish failed", error);
        this.updateActionLoading("publish", false);
        wx.showToast({ title: "报名信息加载失败，无法发布", icon: "none" });
      });
  },

  buildPublishPayload(activity, registrationFields) {
    const detail =
      (activity && activity.rawDetail) || this.currentActivityDetail || null;
    if (!detail) return null;

    const activityID = detail.activityID || (activity && activity.id);
    if (!activityID) return null;

    const registrationStartISO = toISOStringString(detail.registrationStartTime);
    const registrationEndISO = toISOStringString(detail.registrationEndTime);
    if (!registrationStartISO || !registrationEndISO) return null;

    const groupsSource = Array.isArray(detail.activityGroups) ? detail.activityGroups : [];
    if (!groupsSource.length) return null;

    const formattedGroups = groupsSource.map(group => {
      const startISO = toISOStringString(group.groupStartTime);
      const endISO = toISOStringString(group.groupEndTime);
      const count = Number(group.groupRegistrationCount);
      return {
        groupName: group.groupName || "",
        groupStartTime: startISO,
        groupEndTime: endISO,
        groupRegistrationCount:
          Number.isFinite(count) && count >= 0 ? count : 0,
        remark: decodeHTML(group.remark || group.Remark || "")
      };
    });

    return {
      activityID,
      activityName: detail.activityName || activity.name || "",
      activityLocation: detail.activityLocation || activity.location || "",
      registrationStartTime: registrationStartISO,
      registrationEndTime: registrationEndISO,
      activityDetails: detail.activityDetails || "",
      activityImageURL: detail.activityImageURL || "",
      activityRequirements: detail.activityRequirements || "",
      activityGroups: formattedGroups,
      activityFields: Array.isArray(registrationFields)
        ? registrationFields.map(field => ({
            fieldName: field.fieldName || "",
            isOptional: !!field.isOptional
          }))
        : [],
      activityStatus: "Published"
    };
  },

  handleActionTap(event) {
    const dataset = event && event.currentTarget ? event.currentTarget.dataset : null;
    const action = dataset ? dataset.action : "";
    if (!action) return;

    const activity = this.data.activity;
    if (!activity) return;

    if (this.data.actionLoading && this.data.actionLoading[action]) return;

    switch (action) {
      case "register":
        if (!activity.allowSignup) {
          const reason =
            this.describeSignupRestriction({
              statusValue: activity.status ? activity.status.value : "",
              registrationOpen: activity.registrationOpen,
              hasQuota: activity.hasQuota
            }) || "当前暂不可报名";
          wx.showToast({ title: reason, icon: "none" });
          return;
        }
        {
          const app = typeof getApp === "function" ? getApp() : null;
          if (app && typeof app.ensureUserProfileForAction === "function") {
            const allowed = app.ensureUserProfileForAction("报名活动前请先完善个人信息");
            if (!allowed) return;
          }
        }
        this.openRegistrationModal("create");
        break;
      case "update":
        this.openRegistrationModal("update");
        break;
      case "cancel":
        this.confirmCancelRegistration();
        break;
      case "edit":
        if (activity.status && activity.status.value !== "Draft") {
          wx.showToast({ title: "已发布活动无法修改", icon: "none" });
          return;
        }
        this.navigateToEditActivity(activity.id);
        break;
      case "publish":
        if (!activity.status || activity.status.value !== "Draft") {
          wx.showToast({ title: "仅草稿活动可发布", icon: "none" });
          return;
        }
        this.handlePublishActivity(activity);
        break;
      case "manage":
        this.openViewRegistrants();
        break;
      case "withdraw":
        this.handleWithdrawActivity();
        break;
      case "checkin":
        this.handleCheckInAction();
        break;
      case "delete":
        this.confirmDeleteActivity();
        break;
      default:
        wx.showToast({ title: "功能尚未开放", icon: "none" });
    }
  },

  handleCheckInAction() {
    const activity = this.data.activity;
    if (!activity) return;

    const groups = Array.isArray(activity.groups) ? activity.groups : [];
    const isPublisher = !!activity.isPublisher;
    const availableGroups = isPublisher
      ? groups.filter(group => !!group)
      : groups.filter(group => group && group.isCurrentUser);

    if (!availableGroups.length) {
      wx.showToast({
        title: isPublisher ? "暂无分组可管理" : "暂无签到信息",
        icon: "none"
      });
      return;
    }

    this.selectGroupForCheckIn(availableGroups)
      .then(group => {
        if (!group) return;
        if (isPublisher) {
          this.openCheckInManagement(group);
        } else {
          this.handleRegistrantCheckIn(group);
        }
      })
      .catch(error => {
        if (error) {
          console.error("selectGroupForCheckIn failed", error);
        }
      });
  },

  handleRegistrantCheckIn(group, preferredMode, options = {}) {
    if (!group || !group.groupID) return Promise.resolve();
    const mode = preferredMode || "";
    const autoSubmit = options && options.autoSubmit === true;

    return this.fetchGroupCheckInInfo(group, {
      onSuccess: (info, target) =>
        this.promptRegistrantCheckInFlow({
          info,
          group: target,
          preferredMode: mode,
          autoSubmit
        })
    });
  },

  selectGroupForCheckIn(groups) {
    if (!Array.isArray(groups) || groups.length === 0) {
      return Promise.resolve(null);
    }
    if (groups.length === 1) {
      return Promise.resolve(groups[0]);
    }
    const itemList = groups.map(group => (group && group.groupName) || "未命名分组");
    return new Promise(resolve => {
      wx.showActionSheet({
        itemList,
        success: res => {
          if (res && typeof res.tapIndex === "number" && res.tapIndex >= 0 && res.tapIndex < groups.length) {
            resolve(groups[res.tapIndex]);
          } else {
            resolve(null);
          }
        },
        fail: () => resolve(null)
      });
    });
  },

  openCheckInManagement(group) {
    if (!group || !group.groupID) return Promise.resolve();

    return this.fetchGroupCheckInInfo(group, {
      onSuccess: (info, target, codeMap) =>
        this.showCheckInManagementOptions({ info, group: target, codeMap })
    });
  },

  showCheckInManagementOptions({ info, group, codeMap }) {
    const target = group || {};
    const infoPayload = info || {};
    const checkInActive = !!infoPayload.isCheckInActive;
    const checkOutActive = !!infoPayload.isCheckOutActive;

    const managementActions = [];
    managementActions.push({ key: "viewInfo", label: "查看签到信息" });
    managementActions.push({ key: "viewMembers", label: "查看签到人员" });

    const checkInLabel = checkInActive ? "更新签到口令" : "开始签到";
    managementActions.push({ key: "startCheckIn", label: checkInLabel });
    if (checkInActive) {
      managementActions.push({ key: "endCheckIn", label: "结束签到" });
    }

    const checkOutLabel = checkOutActive ? "更新签退口令" : "开始签退";
    managementActions.push({ key: "startCheckOut", label: checkOutLabel });
    if (checkOutActive) {
      managementActions.push({ key: "endCheckOut", label: "结束签退" });
    }

    const canSelfCheck =
      !!(target && target.isCurrentUser) ||
      !!(
        infoPayload &&
        infoPayload.currentUserStatus &&
        infoPayload.currentUserStatus.isCurrentUser
      );

    const participantActions = [];
    if (canSelfCheck && checkInActive) {
      participantActions.push({ key: "doCheckIn", label: "我来签到" });
    }
    if (canSelfCheck && checkOutActive) {
      participantActions.push({ key: "doCheckOut", label: "我要签退" });
    }

    if (!participantActions.length && !managementActions.length) {
      wx.showToast({ title: "暂无签到/签退", icon: "none" });
      return;
    }

    if (!participantActions.length && managementActions.length) {
      wx.showToast({ title: "暂无签到/签退", icon: "none" });
    }

    const allActions = participantActions.concat(managementActions);
    if (!allActions.length) {
      wx.showToast({ title: "暂无可用操作", icon: "none" });
      return;
    }

    const MAX_ACTIONS_PER_SHEET = 6;

    const handleAction = action => {
      switch (action.key) {
        case "viewInfo":
          this.showCheckInInfoModal({ info: infoPayload, group: target, codeMap: codeMap || {} });
          break;
        case "viewMembers":
          this.handleViewCheckInMembers(target);
          break;
        case "startCheckIn":
          this.promptCheckInCode("checkIn").then(code => {
            if (code) {
              this.startGroupCheckIn({ group: target, mode: "checkIn", code });
            }
          });
          break;
        case "endCheckIn":
          this.endGroupCheckIn({ group: target, mode: "checkIn" });
          break;
        case "startCheckOut":
          this.promptCheckInCode("checkOut").then(code => {
            if (code) {
              this.startGroupCheckIn({ group: target, mode: "checkOut", code });
            }
          });
          break;
        case "endCheckOut":
          this.endGroupCheckIn({ group: target, mode: "checkOut" });
          break;
        case "doCheckIn":
          this.promptRegistrantCheckInFlow({
            info: infoPayload,
            group: target,
            preferredMode: "checkIn",
            autoSubmit: true
          });
          break;
        case "doCheckOut":
          this.promptRegistrantCheckInFlow({
            info: infoPayload,
            group: target,
            preferredMode: "checkOut",
            autoSubmit: true
          });
          break;
        default:
          break;
      }
    };

    const presentActionSheet = actionsToShow => {
      if (!Array.isArray(actionsToShow) || !actionsToShow.length) return;

      let displayActions = actionsToShow.slice();
      let overflowActions = [];

      if (displayActions.length > MAX_ACTIONS_PER_SHEET) {
        overflowActions = displayActions.slice(MAX_ACTIONS_PER_SHEET - 1);
        displayActions = displayActions.slice(0, MAX_ACTIONS_PER_SHEET - 1);
        displayActions.push({ key: "__more__", label: "更多操作" });
      }

      const itemList = displayActions.map(item => item.label);
      if (!itemList.length) return;

      const showSheet = () => {
        wx.showActionSheet({
          itemList,
          success: res => {
            if (!res || typeof res.tapIndex !== "number") return;
            const action = displayActions[res.tapIndex];
            if (!action) return;
            if (action.key === "__more__") {
              presentActionSheet(overflowActions);
              return;
            }
            handleAction(action);
          },
          fail: err => {
            if (!err || !err.errMsg) return;
            const message = String(err.errMsg || "");
            if (message.indexOf("cancel") !== -1) return;
            console.error("showActionSheet failed", err);
            wx.showToast({ title: "菜单打开失败，请重试", icon: "none" });
          }
        });
      };

      if (typeof wx.nextTick === "function") {
        wx.nextTick(showSheet);
      } else {
        setTimeout(showSheet, 0);
      }
    };

    presentActionSheet(allActions);
  },

  promptCheckInCode(mode) {
    const isCheckOut = mode === "checkOut";
    const title = isCheckOut ? "设置签退口令" : "设置签到口令";
    const placeholderText = isCheckOut ? "请输入签退口令或链接" : "请输入签到口令或链接";

    return new Promise(resolve => {
      wx.showModal({
        title,
        editable: true,
        placeholderText,
        confirmText: "确定",
        cancelText: "取消",
        success: res => {
          if (!res || !res.confirm) {
            resolve(null);
            return;
          }
          const content = typeof res.content === "string" ? res.content.trim() : "";
          if (!content) {
            wx.showToast({ title: "口令不能为空", icon: "none" });
            resolve(null);
            return;
          }
          resolve(content);
        },
        fail: () => resolve(null)
      });
    });
  },

  startGroupCheckIn({ group, mode, code }) {
    if (!group || !group.groupID || !code) return;
    const activity = this.data.activity;
    if (!activity || !activity.id) return;
    if (this.data.actionLoading && this.data.actionLoading.checkin) return;

    this.updateActionLoading("checkin", true);

    const isCheckOut = mode === "checkOut";
    this.invokeCloudFunction({
      name: "startCheckIn",
      data: { groupID: group.groupID, mode, code },
      loadingTitle: isCheckOut ? "开启签退..." : "开启签到...",
      success: res => {
        const payload = res && (res.result || res.data || res);
        if (payload && payload.success) {
          wx.showToast({ title: isCheckOut ? "签退已开启" : "签到已开启", icon: "success" });
          this.fetchActivityDetail(activity.id);
        } else {
          const message = (payload && (payload.error || payload.message)) || "操作失败，请稍后重试";
          wx.showToast({ title: message, icon: "none" });
        }
      },
      fail: err => {
        console.error("startCheckIn failed", err);
        wx.showToast({ title: "网络异常，操作失败", icon: "none" });
      },
      complete: () => {
        this.updateActionLoading("checkin", false);
      }
    });
  },

  endGroupCheckIn({ group, mode }) {
    if (!group || !group.groupID) return;
    const activity = this.data.activity;
    if (!activity || !activity.id) return;

    const isCheckOut = mode === "checkOut";
    const actionText = isCheckOut ? "签退" : "签到";

    wx.showModal({
      title: "结束",
      content: `确认结束本分组的${actionText}？`,
      confirmText: "结束",
      cancelText: "取消",
      success: res => {
        if (!res || !res.confirm) return;
        if (this.data.actionLoading && this.data.actionLoading.checkin) return;

        this.updateActionLoading("checkin", true);
        this.invokeCloudFunction({
          name: "endCheckIn",
          data: { groupID: group.groupID, mode },
          loadingTitle: "结束...",
          success: response => {
            const payload = response && (response.result || response.data || response);
            if (payload && payload.success) {
              wx.showToast({ title: `${actionText}已结束`, icon: "success" });
              this.fetchActivityDetail(activity.id);
            } else {
              const message =
                (payload && (payload.error || payload.message)) || "操作失败，请稍后重试";
              wx.showToast({ title: message, icon: "none" });
            }
          },
          fail: err => {
            console.error("endCheckIn failed", err);
            wx.showToast({ title: "网络异常，操作失败", icon: "none" });
          },
          complete: () => {
            this.updateActionLoading("checkin", false);
          }
        });
      }
    });
  },

  fetchGroupCheckInInfo(group, options = {}) {
    const target = group || {};
    const groupID = target.groupID || "";
    if (!groupID) {
      wx.showToast({ title: "未找到分组信息", icon: "none" });
      return Promise.resolve(null);
    }
    if (this.data.actionLoading && this.data.actionLoading.checkin) {
      return Promise.resolve(null);
    }

    const { onSuccess } = options || {};

    this.updateActionLoading("checkin", true);

    return new Promise(resolve => {
      this.invokeCloudFunction({
        name: "queryCheckInInfo",
        data: { groupID },
        loadingTitle: "加载签到信息...",
        success: res => {
          const raw = res && (res.result || res.data || res);
          let info = raw;
          let successFlag;
          let errorMessage = "";

          if (raw && typeof raw.success === "boolean") {
            successFlag = raw.success;
            if (raw.success) {
              info = raw.data !== undefined ? raw.data : raw;
            } else {
              errorMessage = raw.error || raw.message || "查询失败，请稍后重试";
            }
          }

          if (successFlag === false || !info) {
            const message = errorMessage || "查询失败，请稍后重试";
            wx.showToast({ title: message, icon: "none" });
            resolve(null);
            return;
          }

          const safeInfo = info || {};

          if (target) {
            if (Object.prototype.hasOwnProperty.call(safeInfo, "isCheckInActive")) {
              target.checkInActive = !!safeInfo.isCheckInActive;
            }
            if (Object.prototype.hasOwnProperty.call(safeInfo, "isCheckOutActive")) {
              target.checkOutActive = !!safeInfo.isCheckOutActive;
            }
            if (Object.prototype.hasOwnProperty.call(safeInfo, "checkInStartTime")) {
              target.checkInStartTime = safeInfo.checkInStartTime || "";
            }
            if (Object.prototype.hasOwnProperty.call(safeInfo, "checkOutStartTime")) {
              target.checkOutStartTime = safeInfo.checkOutStartTime || "";
            }
            if (Object.prototype.hasOwnProperty.call(safeInfo, "checkInCodeOrURL")) {
              target.checkInCode = safeInfo.checkInCodeOrURL || "";
            }
            if (Object.prototype.hasOwnProperty.call(safeInfo, "checkOutCodeOrURL")) {
              target.checkOutCode = safeInfo.checkOutCodeOrURL || "";
            }
            if (safeInfo.currentUserStatus) {
              target.currentUserStatus = safeInfo.currentUserStatus;
              const statusInfo = safeInfo.currentUserStatus;
              const isCurrent =
                typeof statusInfo.isCurrentUser === "boolean"
                  ? statusInfo.isCurrentUser
                  : true;
              if (isCurrent) {
                target.isCurrentUser = true;
              }
            }
          }

          const codes = [];
          if (safeInfo.checkInCodeOrURL) codes.push(safeInfo.checkInCodeOrURL);
          if (safeInfo.checkOutCodeOrURL) codes.push(safeInfo.checkOutCodeOrURL);

          const proceed = codeMap => {
            this.updateActionLoading("checkin", false);
            const safeResult = { info: safeInfo, group: target, codeMap: codeMap || {} };

            if (typeof onSuccess === "function") {
              try {
                const outcome = onSuccess(safeInfo, target, codeMap || {});
                Promise.resolve(outcome)
                  .then(value => resolve(value !== undefined ? value : safeResult))
                  .catch(error => {
                    console.error("handle check-in callback failed", error);
                    resolve(safeResult);
                  });
              } catch (error) {
                console.error("handle check-in callback failed", error);
                resolve(safeResult);
              }
              return;
            }

            this.showCheckInInfoModal({ info: safeInfo, group: target, codeMap: codeMap || {} });
            resolve(safeResult);
          };

          this.resolveCheckInCodeURLs(codes)
            .then(map => proceed(map))
            .catch(() => proceed({}));
        },
        fail: err => {
          console.error("queryCheckInInfo failed", err);
          wx.showToast({ title: "查询失败，请稍后重试", icon: "none" });
          resolve(null);
        },
        complete: () => {
          this.updateActionLoading("checkin", false);
        }
      });
    });
  },

  promptRegistrantCheckInFlow({ info, group, preferredMode, autoSubmit }) {
    if (!info || !group) {
      return Promise.resolve();
    }

    const actions = [];
    if (info.isCheckInActive) actions.push({ key: "checkIn", label: "签到" });
    if (info.isCheckOutActive) {
      actions.push({ key: "checkOut", label: "签退" });
    }

    if (actions.length === 0) {
      wx.showToast({ title: "暂无签到/签退", icon: "none" });
      return Promise.resolve();
    }

    const runAction = mode =>
      new Promise(resolve => {
        this.promptRegistrantCheckIn({ group, mode })
          .then(code => {
            if (code) {
              this.submitGroupCheckIn({ group, code, mode });
            }
          })
          .finally(() => resolve());
      });

    const defaultAction = preferredMode
      ? actions.find(action => action.key === preferredMode)
      : null;

    if (autoSubmit) {
      if (defaultAction) {
        return runAction(defaultAction.key);
      }
      if (actions.length === 1) {
        return runAction(actions[0].key);
      }
    } else if (defaultAction) {
      return runAction(defaultAction.key);
    }

    if (actions.length === 1) {
      return runAction(actions[0].key);
    }

    return new Promise(resolve => {
      wx.showActionSheet({
        itemList: actions.map(item => item.label),
        success: res => {
          if (!res || typeof res.tapIndex !== "number") {
            resolve();
            return;
          }
          const action = actions[res.tapIndex];
          if (!action) {
            resolve();
            return;
          }
          runAction(action.key).then(() => resolve());
        },
        fail: () => resolve()
      });
    });
  },

  promptRegistrantCheckIn({ group, mode }) {
    const target = group || {};
    const isCheckOut = mode === "checkOut";
    const prefix = target.groupName ? target.groupName : "当前分组";
    const title = `${prefix}${isCheckOut ? "签退" : "签到"}`;
    const placeholderText = isCheckOut ? "请输入签退口令" : "请输入签到口令";
    const confirmText = isCheckOut ? "签退" : "签到";

    return new Promise(resolve => {
      wx.showModal({
        title,
        editable: true,
        placeholderText,
        confirmText,
        cancelText: "取消",
        success: res => {
          if (!res || !res.confirm) {
            resolve(null);
            return;
          }
          const content = typeof res.content === "string" ? res.content.trim() : "";
          if (!content) {
            wx.showToast({ title: "口令不能为空", icon: "none" });
            resolve(null);
            return;
          }
          resolve(content);
        },
        fail: () => resolve(null)
      });
    });
  },

  submitGroupCheckIn({ group, code, mode }) {
    const target = group || {};
    if (!target.groupID || !code) return;
    const activity = this.data.activity;
    if (!activity || !activity.id) return;
    if (this.data.actionLoading && this.data.actionLoading.checkin) return;

    const app = typeof getApp === "function" ? getApp() : null;
    const globalData = (app && app.globalData) || {};
    const userInfo = globalData.userInfo || {};
    const openID = userInfo.openID || globalData.openID || "";
    if (!openID) {
      wx.showToast({ title: "未获取到用户身份，请稍后重试", icon: "none" });
      return;
    }

    const isCheckOut = mode === "checkOut";

    this.updateActionLoading("checkin", true);

    this.invokeCloudFunction({
      name: "checkIn",
      data: {
        groupID: target.groupID,
        code,
        openID,
        isCheckIn: !isCheckOut,
        mode: mode || (isCheckOut ? "checkOut" : "checkIn")
      },
      loadingTitle: isCheckOut ? "签退中..." : "签到中...",
      success: res => {
        const payload = res && (res.result || res.data || res);
        if (payload && payload.success) {
          wx.showToast({ title: isCheckOut ? "签退成功" : "签到成功", icon: "success" });
          this.fetchActivityDetail(activity.id);
        } else {
          const fallbackMessage = isCheckOut
            ? "签退失败，口令不正确或已失效"
            : "签到失败，口令不正确或已失效";
          const message =
            (payload && (payload.error || payload.message)) || fallbackMessage;
          wx.showToast({ title: message, icon: "none" });
        }
      },
      fail: err => {
        console.error("checkIn failed", err);
        wx.showToast({
          title: isCheckOut ? "签退失败，请稍后重试" : "签到失败，请稍后重试",
          icon: "none"
        });
      },
      complete: () => {
        this.updateActionLoading("checkin", false);
      }
    });
  },

  handleViewCheckInMembers(group) {
    const activity = this.data.activity;
    if (!activity || !activity.id) {
      wx.showToast({ title: "未找到活动信息", icon: "none" });
      return;
    }

    const target = group || {};
    const groupID = target.groupID || target.GroupID || "";

    const params = [
      "mode=checkin",
      `activityID=${encodeURIComponent(activity.id)}`
    ];
    if (groupID) {
      params.push(`groupID=${encodeURIComponent(groupID)}`);
    }

    wx.navigateTo({
      url: `/pages/participant-viewer/participant-viewer?${params.join("&")}`
    });
  },

  fetchGroupCheckInMembers(group) {
    const target = group || {};
    const groupID = target.groupID || "";
    if (!groupID) {
      wx.showToast({ title: "未找到分组信息", icon: "none" });
      return Promise.resolve(null);
    }

    this.updateActionLoading("checkin", true);

    return new Promise(resolve => {
      this.invokeCloudFunction({
        name: "queryRegistrantCheckInInfo",
        data: { groupID },
        loadingTitle: "获取签到名单...",
        success: res => {
          const payload = res && (res.result || res.data || res);
          if (payload && payload.success) {
            resolve({
              checkInRegistrants: payload.checkInRegistrants || [],
              checkOutRegistrants: payload.checkOutRegistrants || []
            });
          } else {
            const message =
              (payload && (payload.error || payload.message)) || "获取签到名单失败";
            wx.showToast({ title: message, icon: "none" });
            resolve(null);
          }
        },
        fail: err => {
          console.error("queryRegistrantCheckInInfo failed", err);
          wx.showToast({ title: "获取签到名单失败", icon: "none" });
          resolve(null);
        },
        complete: () => {
          this.updateActionLoading("checkin", false);
        }
      });
    });
  },
  resolveCheckInCodeURLs(codes) {
    const list = Array.isArray(codes)
      ? Array.from(new Set(codes.filter(code => typeof code === "string" && code.startsWith("cloud://"))))
      : [];

    if (list.length === 0) {
      return Promise.resolve({});
    }

    if (!wx.cloud || typeof wx.cloud.getTempFileURL !== "function") {
      return Promise.resolve({});
    }

    return wx.cloud
      .getTempFileURL({ fileList: list })
      .then(res => {
        const map = {};
        const files = res && res.fileList ? res.fileList : [];
        files.forEach(file => {
          if (file.status === 0 && file.tempFileURL) {
            map[file.fileID] = file.tempFileURL;
          }
        });
        return map;
      })
      .catch(err => {
        console.error("getTempFileURL failed", err);
        return {};
      });
  },

  resolveCheckInCodeAsset(code, codeMap) {
    if (!code) {
      return { display: "", preview: "" };
    }
    const text = typeof code === "string" ? code.trim() : "";
    if (!text) {
      return { display: "", preview: "" };
    }
    if (codeMap && codeMap[text]) {
      return { display: text, preview: codeMap[text] };
    }
    if (/^https?:\/\//i.test(text)) {
      return { display: text, preview: text };
    }
    return { display: text, preview: "" };
  },

  showCheckInInfoModal({ info, group, codeMap }) {
    const formatTime = value => {
      const date = toDate(value);
      return date ? this.formatDate(date) : "";
    };

    const checkInTime = formatTime(info.checkInStartTime);
    const checkOutTime = formatTime(info.checkOutStartTime);

    const checkInAsset = this.resolveCheckInCodeAsset(info.checkInCodeOrURL, codeMap);
    const checkOutAsset = this.resolveCheckInCodeAsset(info.checkOutCodeOrURL, codeMap);

    const lines = [];
    if (checkInTime) {
      lines.push("签到开始：" + checkInTime);
    }
    lines.push(`签到状态：${info.isCheckInActive ? "进行中" : "未开启"}`);
    if (checkInAsset.preview) {
      lines.push("签到凭证：二维码，可点击查看");
    } else if (checkInAsset.display) {
      lines.push("签到凭证：" + checkInAsset.display);
    }

    if (checkOutTime) {
      lines.push("签退开始：" + checkOutTime);
    }
    lines.push(`签退状态：${info.isCheckOutActive ? "进行中" : "未开启"}`);
    if (checkOutAsset.preview) {
      lines.push("签退凭证：二维码，可点击查看");
    } else if (checkOutAsset.display) {
      lines.push("签退凭证：" + checkOutAsset.display);
    }

    if (lines.length === 0) {
      lines.push("暂无签到信息");
    }

    const previewUrls = [checkInAsset.preview, checkOutAsset.preview].filter(Boolean);
    const hasPreview = previewUrls.length > 0;
    const title = group && group.groupName ? `${group.groupName}签到信息` : "签到信息";

    wx.showModal({
      title,
      content: lines.join("\n"),
      showCancel: hasPreview,
      confirmText: hasPreview ? "查看二维码" : "我知道了",
      cancelText: hasPreview ? "我知道了" : "取消",
      confirmColor: "#2563eb",
      success: res => {
        if (!res) return;
        if (hasPreview && res.confirm) {
          wx.previewImage({ urls: previewUrls });
        }
      }
    });
  },

  handleWithdrawActivity() {
    const activity = this.data.activity;
    if (!activity || !activity.id) return;
    if (this.data.actionLoading && this.data.actionLoading.withdraw) return;

    wx.showModal({
      title: "下架活动",
      content: "下架后报名将停止，确认继续？",
      confirmText: "下架",
      confirmColor: "#ef4444",
      cancelText: "保留",
      success: res => {
        if (!res || !res.confirm) return;
        this.updateActionLoading("withdraw", true);
        this.invokeCloudFunction({
          name: "withdrawActivity",
          data: { activityID: activity.id },
          loadingTitle: "处理中...",
          success: response => {
            const payload = response && (response.result || response.data || response);
            if (payload && payload.success) {
              wx.showToast({ title: "活动已下架", icon: "success" });
              this.fetchActivityDetail(activity.id);
            } else {
              wx.showToast({
                title: (payload && payload.error) || "下架失败，请稍后重试",
                icon: "none"
              });
            }
          },
          fail: err => {
            console.error("withdrawActivity failed", err);
            wx.showToast({ title: "网络异常，请稍后重试", icon: "none" });
          },
          complete: () => {
            this.updateActionLoading("withdraw", false);
          }
        });
      }
    });
  },

  confirmDeleteActivity() {
    const activity = this.data.activity;
    if (!activity || !activity.id) return;
    if (activity.status && activity.status.value !== "Draft") {
      wx.showToast({ title: "仅草稿活动可删除", icon: "none" });
      return;
    }
    if (this.data.actionLoading && this.data.actionLoading.delete) return;

    wx.showModal({
      title: "删除活动",
      content: "删除后将无法恢复，确认继续？",
      confirmText: "删除",
      confirmColor: "#ef4444",
      cancelText: "再想想",
      success: res => {
        if (!res || !res.confirm) return;
        this.updateActionLoading("delete", true);
        this.invokeCloudFunction({
          name: "deleteActivity",
          data: { activityID: activity.id },
          loadingTitle: "删除中...",
          success: response => {
            const payload = response && (response.result || response.data || response);
            if (payload && payload.success) {
              wx.showToast({ title: "活动已删除", icon: "success" });
              setTimeout(() => {
                const pages = typeof getCurrentPages === "function" ? getCurrentPages() : [];
                if (pages && pages.length > 1) {
                  wx.navigateBack({ delta: 1 });
                } else {
                  wx.reLaunch({ url: "/pages/home/home" });
                }
              }, 800);
            } else {
              const message = (payload && (payload.error || payload.message)) || "删除失败，请稍后重试";
              wx.showToast({ title: message, icon: "none" });
            }
          },
          fail: err => {
            console.error("deleteActivity failed", err);
            wx.showToast({ title: "网络异常，删除失败", icon: "none" });
          },
          complete: () => {
            this.updateActionLoading("delete", false);
          }
        });
      }
    });
  },

  openRegistrationModal(mode) {
    const activity = this.data.activity;
    if (!activity) return;

    const defaultSelectionRaw =
      mode === "update" && Array.isArray(activity.joinedGroupIDs)
        ? activity.joinedGroupIDs.slice()
        : this.getDefaultGroupSelection(activity);
    const defaultSelection = Array.isArray(defaultSelectionRaw)
      ? Array.from(new Set(defaultSelectionRaw.filter(Boolean)))
      : [];
    const defaultSelectionMap = buildSelectionMap(defaultSelection);

    this.setData({
      registrationModal: createRegistrationModalState({
        visible: true,
        mode,
        loading: true,
        selectedGroupIDs: defaultSelection,
        selectionMap: defaultSelectionMap,
        canCancel: mode === "update" && !!activity.isPublisher && !!activity.isRegistrant
      })
    });

    const fieldsPromise = this.loadRegistrationFields(activity.id);
    const registrationInfoPromise =
      mode === "update" ? this.loadRegistrationInfo(activity.id) : Promise.resolve(null);

    Promise.all([fieldsPromise, registrationInfoPromise])
      .then(([fieldResult, registrationInfo]) => {
        const fieldsRaw = (fieldResult && fieldResult.fields) || [];
        const fieldValueMap = new Map();
        if (registrationInfo && Array.isArray(registrationInfo.registrationFields)) {
          registrationInfo.registrationFields.forEach(field => {
            const fieldID = field.fieldID || field.FieldID;
            if (fieldID) {
              fieldValueMap.set(fieldID, field.fieldContent || field.FieldContent || "");
            }
          });
        }

        const fields = fieldsRaw.map(field => ({
          fieldID: field.fieldID,
          fieldName: field.fieldName || "",
          isOptional: !!field.isOptional,
          value: fieldValueMap.get(field.fieldID) || ""
        }));

        const selectedFromInfo =
          registrationInfo && Array.isArray(registrationInfo.registrationGroups)
            ? registrationInfo.registrationGroups
                .map(group => group.GroupID || group.groupID || "")
                .filter(Boolean)
            : [];

        const nextSelectedGroupIDs =
          mode === "update"
            ? Array.from(
                new Set(
                  (selectedFromInfo.length > 0 ? selectedFromInfo : defaultSelection).filter(Boolean)
                )
              )
            : defaultSelection;
        const nextSelectionMap = buildSelectionMap(nextSelectedGroupIDs);

        const needCollectInfo = !!(
          (fieldResult && fieldResult.needCollectInfo) ||
          (registrationInfo &&
            Array.isArray(registrationInfo.registrationFields) &&
            registrationInfo.registrationFields.length > 0)
        );

        this.setData({
          "registrationModal.loading": false,
          "registrationModal.needCollectInfo": needCollectInfo,
          "registrationModal.fields": fields,
          "registrationModal.selectedGroupIDs": nextSelectedGroupIDs,
          "registrationModal.selectionMap": nextSelectionMap,
          "registrationModal.error": ""
        });
      })
      .catch(message => {
        this.setData({
          "registrationModal.loading": false,
          "registrationModal.needCollectInfo": false,
          "registrationModal.fields": [],
          "registrationModal.error":
            message || "获取报名信息失败，可稍后重试或直接提交基础信息"
        });
      });
  },

  getDefaultGroupSelection(activity) {
    const groups = Array.isArray(activity.groups) ? activity.groups : [];
    const selectable = groups.filter(group => group.isSelectable);
    if (selectable.length === 1) {
      return [selectable[0].groupID];
    }
    return [];
  },

  loadRegistrationFields(activityId, options = {}) {
    const { showLoading = true } = options;
    if (!activityId) {
      return Promise.resolve({ needCollectInfo: false, fields: [] });
    }

    if (this.registrationFieldCache && this.registrationFieldCache[activityId]) {
      return Promise.resolve(this.registrationFieldCache[activityId]);
    }

    return new Promise(resolve => {
      this.invokeCloudFunction({
        name: "queryActivityRegisterInfoCollection",
        data: { activityID: activityId },
        loadingTitle: "加载中...",
        showLoading,
        success: res => {
          const payload = res && (res.result || res.data || res);
          const result = {
            needCollectInfo: !!(payload && payload.needCollectInfo),
            fields: Array.isArray(payload && payload.fields) ? payload.fields : []
          };
          this.registrationFieldCache[activityId] = result;
          resolve(result);
        },
        fail: err => {
          console.error("queryActivityRegisterInfoCollection failed", err);
          if (showLoading) {
            wx.showToast({
              title: "报名信息加载失败，默认仅提交基础信息",
              icon: "none"
            });
          }
          const fallback = { needCollectInfo: false, fields: [] };
          this.registrationFieldCache[activityId] = fallback;
          resolve(fallback);
        }
      });
    });
  },

  ensureRegistrationFieldDefinitions(activityId) {
    if (!activityId) {
      return Promise.resolve(buildRegistrationFieldDefinitions([]));
    }

    const cached = this.registrationFieldCache && this.registrationFieldCache[activityId];
    if (cached && Array.isArray(cached.fields)) {
      return Promise.resolve(buildRegistrationFieldDefinitions(cached.fields));
    }

    return this.loadRegistrationFields(activityId, { showLoading: false }).then(result =>
      buildRegistrationFieldDefinitions(result.fields || [])
    );
  },

  loadRegistrationInfo(activityId) {
    if (!activityId) return Promise.resolve(null);

    if (this.registrationInfoCache && this.registrationInfoCache[activityId]) {
      return Promise.resolve(this.registrationInfoCache[activityId]);
    }

    return new Promise(resolve => {
      this.invokeCloudFunction({
        name: "queryRegistrationInfo",
        data: { activityID: activityId },
        loadingTitle: "加载中...",
        success: res => {
          const payload = res && (res.result || res.data || res);
          if (payload && payload.success && payload.data) {
            this.registrationInfoCache[activityId] = payload.data;
            resolve(payload.data);
          } else {
            resolve(null);
          }
        },
        fail: err => {
          console.error("queryRegistrationInfo failed", err);
          resolve(null);
        }
      });
    });
  },


  openViewRegistrants(initialGroupID = "") {
    const activity = this.data.activity;
    if (!activity || !activity.id) return;

    const params = [
      "mode=registrants",
      `activityID=${encodeURIComponent(activity.id)}`
    ];
    if (initialGroupID) {
      params.push(`groupID=${encodeURIComponent(initialGroupID)}`);
    }

    wx.navigateTo({
      url: `/pages/participant-viewer/participant-viewer?${params.join("&")}`
    });
  },

  handleGroupCardTap(event) {
    const activity = this.data.activity;
    if (!activity || !activity.id || !activity.isPublisher) return;
    const dataset = event && event.currentTarget ? event.currentTarget.dataset : null;
    const groupId = dataset && dataset.groupId ? String(dataset.groupId) : "";

    const params = [
      "mode=registrants",
      `activityID=${encodeURIComponent(activity.id)}`
    ];
    if (groupId) {
      params.push(`groupID=${encodeURIComponent(groupId)}`);
    }

    wx.navigateTo({
      url: `/pages/participant-viewer/participant-viewer?${params.join("&")}`
    });
  },
  handleGroupToggle(event) {
    const modal = this.data.registrationModal;
    if (!modal || !modal.visible || modal.submitting || modal.loading) return;
    const dataset = event && event.currentTarget ? event.currentTarget.dataset : {};
    const groupId = dataset && dataset.groupId ? String(dataset.groupId) : "";
    const disabled = dataset && String(dataset.disabled) === "true";
    if (!groupId || disabled) return;
    const selected = Array.isArray(modal.selectedGroupIDs) ? modal.selectedGroupIDs.slice() : [];
    const index = selected.indexOf(groupId);
    if (index === -1) selected.push(groupId);
    else selected.splice(index, 1);
    const selectionMap = buildSelectionMap(selected);
    this.setData({
      "registrationModal.selectedGroupIDs": selected,
      "registrationModal.selectionMap": selectionMap,
      "registrationModal.error": ""
    });
  },

  handleRegistrationFieldInput(event) {
    const fieldId = event && event.currentTarget ? event.currentTarget.dataset.fieldId : "";
    const value = (event && event.detail && event.detail.value) || "";
    if (!fieldId) return;
    const fields = this.data.registrationModal.fields || [];
    const index = fields.findIndex(field => field.fieldID === fieldId);
    if (index === -1) return;
    this.setData({
      [`registrationModal.fields[${index}].value`]: value,
      "registrationModal.error": ""
    });
  },

  handleRegistrationCancelTap() {
    const modal = this.data.registrationModal;
    if (!modal || !modal.visible || modal.submitting || modal.loading) return;
    this.confirmCancelRegistration({ fromModal: true });
  },

  handleRegistrationSubmit() {
    const activity = this.data.activity;
    const modal = this.data.registrationModal;
    if (!activity || !modal.visible || modal.submitting || modal.loading) return;

    const selectedGroupIDs = Array.isArray(modal.selectedGroupIDs)
      ? modal.selectedGroupIDs.filter(Boolean)
      : [];
    if (selectedGroupIDs.length === 0) {
      this.setData({ "registrationModal.error": "请选择至少一个报名分组" });
      return;
    }

    const fields = (modal.fields || []).map(field => ({
      fieldID: field.fieldID,
      fieldName: field.fieldName || "",
      isOptional: field.isOptional,
      value: (field.value || "").trim()
    }));

    const missingField = fields.find(field => !field.isOptional && !field.value);
    if (missingField) {
      this.setData({ "registrationModal.error": `${missingField.fieldName}为必填项` });
      return;
    }

    const payloadFields = fields
      .filter(field => field.value || !field.isOptional)
      .map(field => {
        const base = { fieldID: field.fieldID, fieldContent: field.value };
        if (this.data.registrationModal.mode !== "update") {
          base.fieldName = field.fieldName;
        }
        return base;
      });

    const fnName =
      this.data.registrationModal.mode === "update" ? "alterRegistrationInfo" : "registerActivity";

    const payload =
      this.data.registrationModal.mode === "update"
        ? { activityID: activity.id, registrationGroups: selectedGroupIDs, registrationFields: payloadFields }
        : { activityID: activity.id, groupIDs: selectedGroupIDs, registrationFields: payloadFields };

    const successMessage =
      this.data.registrationModal.mode === "update" ? "报名信息已更新" : "报名成功";

    this.setData({ "registrationModal.submitting": true, "registrationModal.error": "" });

    this.invokeCloudFunction({
      name: fnName,
      data: payload,
      loadingTitle: "提交中...",
      success: res => {
        const result = res && (res.result || res.data || res);
        if (result && result.success) {
          wx.showToast({ title: successMessage, icon: "success" });
          this.closeRegistrationModal();
          this.fetchActivityDetail(activity.id);
        } else {
          const error = (result && result.error) || "操作失败，请稍后重试";
          this.setData({ "registrationModal.error": error });
        }
      },
      fail: err => {
        console.error(`${fnName} failed`, err);
        this.setData({ "registrationModal.error": "网络异常，请稍后重试" });
      },
      complete: () => {
        this.setData({ "registrationModal.submitting": false });
      }
    });
  },

  handleRegistrationMaskTap() {
    if (this.data.registrationModal.submitting) return;
    this.closeRegistrationModal();
  },

  handleRegistrationClose() {
    if (this.data.registrationModal.submitting) return;
    this.closeRegistrationModal();
  },

  closeRegistrationModal() {
    this.setData({ registrationModal: createRegistrationModalState() });
  },

  confirmCancelRegistration(options = {}) {
    const { fromModal = false } = options;
    const activity = this.data.activity;
    if (!activity) return;

    if (!fromModal) {
      if (this.data.actionLoading && this.data.actionLoading.cancel) return;
    } else {
      const modal = this.data.registrationModal;
      if (!modal || !modal.visible || modal.submitting || modal.loading) return;
    }

    wx.showModal({
      title: "取消报名",
      content: "确定要取消此次活动的报名吗？",
      confirmText: "确认取消",
      cancelText: "暂不取消",
      success: res => {
        if (!res || !res.confirm) return;

        if (fromModal) {
          this.closeRegistrationModal();
        } else {
          this.updateActionLoading("cancel", true);
        }

        this.invokeCloudFunction({
          name: "cancelRegistration",
          data: { activityID: activity.id },
          loadingTitle: "处理中...",
          success: cancelRes => {
            const result = cancelRes && (cancelRes.result || cancelRes.data || cancelRes);
            if (result && result.success) {
              wx.showToast({ title: "已取消报名", icon: "success" });
              this.fetchActivityDetail(activity.id);
            } else {
              const error = (result && result.error) || "取消失败，请稍后重试";
              wx.showToast({ title: error, icon: "none" });
            }
          },
          fail: err => {
            console.error("cancelRegistration failed", err);
            wx.showToast({ title: "网络异常，取消失败", icon: "none" });
          },
          complete: () => {
            if (!fromModal) {
              this.updateActionLoading("cancel", false);
            }
          }
        });
      }
    });
  },

  updateActionLoading(actionKey, value) {
    this.setData({ [`actionLoading.${actionKey}`]: !!value });
  },

  isCurrentUserPublisher(openID) {
    if (!openID) return false;
    const app = typeof getApp === "function" ? getApp() : null;
    const globalUser = (app && app.globalData && app.globalData.userInfo) || {};
    const currentOpenID = globalUser.openID || (app && app.globalData && app.globalData.openID) || "";
    return !!currentOpenID && openID === currentOpenID;
  },

  invokeCloudFunction(options = {}) {
    const app = typeof getApp === "function" ? getApp() : null;
    if (app && typeof app.callCloudFunction === "function") {
      return app.callCloudFunction(options);
    }

    const { loadingTitle, showLoading = true, ...callOptions } = options;
    const title =
      typeof loadingTitle === "string" && loadingTitle.trim() ? loadingTitle.trim() : "加载中...";
    const shouldShow = showLoading !== false;

    if (shouldShow) {
      wx.showLoading({ title, mask: true });
    }

    const { success, fail, complete } = callOptions;

    callOptions.success = (...args) => {
      if (typeof success === "function") {
        try {
          success(...args);
        } catch (error) {
          console.error("invokeCloudFunction success 回调异常", error);
        }
      }
    };

    callOptions.fail = (...args) => {
      if (typeof fail === "function") {
        try {
          fail(...args);
        } catch (error) {
          console.error("invokeCloudFunction fail 回调异常", error);
        }
      }
    };

    callOptions.complete = (...args) => {
      if (shouldShow) {
        wx.hideLoading();
      }
      if (typeof complete === "function") {
        try {
          complete(...args);
        } catch (error) {
          console.error("invokeCloudFunction complete 回调异常", error);
        }
      }
    };

    return wx.cloud.callFunction(callOptions);
  },

  onShareAppMessage() {
    const activity = this.data.activity;
    if (!activity) {
      return { title: "活动详情", path: "/pages/activity-detail/activity-detail" };
    }
    return {
      title: activity.name || "活动详情",
      path: `/pages/activity-detail/activity-detail?activityID=${activity.id}`
    };
  }
});

